#include "mg_EEPROM_bsp.h"
#include "mg_Rs485Protocol.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 毫秒级延时（非阻塞）
static void EEP_Delay_Ms(uint32_t ms)
{
	usleep(1000 * ms);
}
//初始化EEPROM引脚
void Eeprom_GPIO_Init(void)
{
	ithGpioSetMode(EEPROM_WP_Pin, ITH_GPIO_MODE0);
	ithGpioSetOut(EEPROM_WP_Pin);
}
//打开写保护
static void Set_EEP_WP(void)
{
	ithGpioSet(EEPROM_WP_Pin);
}
//禁止写保护
static void Clr_EEP_WP(void)
{
	ithGpioClear(EEPROM_WP_Pin);
}

//---------------------------------------------------------------
// 函数名称: BSP_EEP_ReadOneByte
// 功能描述: 读一个字节
// 输入参数: 地址
// 返回参数: 读到的字节
//---------------------------------------------------------------
uint8_t BSP_EEP_ReadOneByte(uint32_t ReadAddr)
{
	uint8_t Addr_Bit16 = (ReadAddr >> 16) & 0x01;
	uint8_t Haddr = (ReadAddr >> 8) & 0xFF;
	uint8_t Laddr = (ReadAddr >> 0) & 0xFF;
	if (EE_TYPE <= AT24C512)
		return (I2C0_Read_16Reg(EEP_IIC_ADDR, Haddr, Laddr));
	else
		return (I2C0_Read_16Reg(EEP_IIC_ADDR | Addr_Bit16, Haddr, Laddr));
}

//---------------------------------------------------------------
// 函数名称: BSP_EEP_WriteOneByte
// 功能描述: 写一个字节
// 输入参数: 地址，数据
// 返回参数: 无
//---------------------------------------------------------------
void BSP_EEP_WriteOneByte(uint32_t WriteAddr, uint8_t DataToWrite)
{
	uint8_t Addr_Bit16 = (WriteAddr >> 16) & 0x01;
	uint8_t Haddr = (WriteAddr >> 8) & 0xFF;
	uint8_t Laddr = (WriteAddr >> 0) & 0xFF;

	Clr_EEP_WP();
	if (EE_TYPE <= AT24C512)
		I2C0_Write_16Reg(EEP_IIC_ADDR, Haddr, Laddr, &DataToWrite, 1);
	else
		I2C0_Write_16Reg(EEP_IIC_ADDR | Addr_Bit16, Haddr, Laddr, &DataToWrite, 1);
	EEP_Delay_Ms(5);
	Set_EEP_WP();
}

//---------------------------------------------------------------
// 函数名称: BSP_EEP_ReadMoreBytes
// 功能描述: 在BSP_EEP指定地址连续读取一定字节的数据（这个读是随机的）
// 输入参数: 开始读数的地址,存放数据的指针，要读取的个数
// 返回参数: 无
//---------------------------------------------------------------
void BSP_EEP_ReadMoreBytes(uint32_t ReadAddr, uint8_t *pBuffer, uint32_t NumToRead)
{
	uint8_t Addr_Bit16 = (ReadAddr >> 16) & 0x01;
	uint8_t Haddr = (ReadAddr >> 8) & 0xFF;
	uint8_t Laddr = (ReadAddr >> 0) & 0xFF;

	if (EE_TYPE <= AT24C512)
		I2C0_Read_More_16Reg(EEP_IIC_ADDR, Haddr, Laddr, pBuffer, NumToRead);
	else
		I2C0_Read_More_16Reg(EEP_IIC_ADDR | Addr_Bit16, Haddr, Laddr, pBuffer, NumToRead);
}

//---------------------------------------------------------------
// 函数名称: BSP_EEP_SequentialWrite
// 功能描述: 在BSP_EEP指定地址连续写入一定字节的数据（不能超过一页）
// 输入参数: 开始地址，要写数据指针，要写数据个数(长度不超过256)
// 返回参数: 无
//---------------------------------------------------------------
void BSP_EEP_SequentialWrite(uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite)
{
	uint8_t Addr_Bit16 = (WriteAddr >> 16) & 0x01;
	uint8_t Haddr = (WriteAddr >> 8) & 0xFF;
	uint8_t Laddr = (WriteAddr >> 0) & 0xFF;

	Clr_EEP_WP();
	if (EE_TYPE <= AT24C512)
		I2C0_Write_16Reg(EEP_IIC_ADDR, Haddr, Laddr, pBuffer, NumToWrite);
	else
		I2C0_Write_16Reg(EEP_IIC_ADDR | Addr_Bit16, Haddr, Laddr, pBuffer, NumToWrite);
	EEP_Delay_Ms(5);
	Set_EEP_WP();
}

//---------------------------------------------------------------
// 函数名称: BSP_EEP_WriteMoreBytes
// 功能描述: 随机写连续字节（程序会自动换页）
// 输入参数: 开始地址，要写数据指针，要写数据个数
// 返回参数: 无
//---------------------------------------------------------------
void BSP_EEP_WriteMoreBytes(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumToWrite)
{
	uint8_t tAddIndex;	//所在页的相对地址（0-255）
	uint8_t tByteCount;	//当前页还剩余的字节数
	uint8_t NumOfPage;	//需要写入整页的页数
	uint8_t NumOfSingle;//需要写入非整页的字节数
	uint8_t temp;
	//先看这页多少乘
	tAddIndex = WriteAddr % EE_PAGE_SIZE; // 所写位置在那
	tByteCount = EE_PAGE_SIZE - tAddIndex;
	NumOfPage = NumToWrite / EE_PAGE_SIZE;
	NumOfSingle = NumToWrite % EE_PAGE_SIZE;

	if (tAddIndex == 0) // 从一页的0处开始写
	{
		if (NumOfPage == 0) // 如果没有一整页
		{
			BSP_EEP_SequentialWrite(WriteAddr, pBuffer, NumToWrite);
		}
		else // 如果有一页
		{
			while (NumOfPage--)
			{
				BSP_EEP_SequentialWrite(WriteAddr, pBuffer, EE_PAGE_SIZE);
				WriteAddr += EE_PAGE_SIZE;
				pBuffer += EE_PAGE_SIZE;
			}
			BSP_EEP_SequentialWrite(WriteAddr, pBuffer, NumOfSingle);
		}
	}
	else // 如果不是从一页开始处写
	{
		if (NumOfPage == 0) // 如果没有一整页码
		{
			if (NumOfSingle > tByteCount) // 如果当前要写的地址所在页不够
			{
				temp = NumOfSingle - tByteCount;
				BSP_EEP_SequentialWrite(WriteAddr, pBuffer, tByteCount);
				WriteAddr += tByteCount;
				pBuffer += tByteCount;
				BSP_EEP_SequentialWrite(WriteAddr, pBuffer, temp);
			}
			else
			{
				BSP_EEP_SequentialWrite(WriteAddr, pBuffer, NumToWrite);
			}
		}
		else // 如果有整页
		{
			NumToWrite -= tByteCount;
			NumOfPage = NumToWrite / EE_PAGE_SIZE;
			NumOfSingle = NumToWrite % EE_PAGE_SIZE;

			BSP_EEP_SequentialWrite(WriteAddr, pBuffer, tByteCount);
			WriteAddr += tByteCount;
			pBuffer += tByteCount;

			while (NumOfPage--)
			{
				BSP_EEP_SequentialWrite(WriteAddr, pBuffer, EE_PAGE_SIZE);
				WriteAddr += EE_PAGE_SIZE;
				pBuffer += EE_PAGE_SIZE;
			}
			if (NumOfSingle != 0)
			{
				BSP_EEP_SequentialWrite(WriteAddr, pBuffer, NumOfSingle);
			}
		}
	}
}
//--------------------------------------------------------------
// 函数名称: BSP_EEPROM_Save
// 功能描述: 保存数据至EEPROM
// 输入参数: Data:数据指针 DataLen:数据长度 EEaddr:EEPROM起始地址
// 返回参数: true
//---------------------------------------------------------------
uint8_t BSP_EEPROM_Save(uint32_t EEaddr, uint8_t* Data, uint32_t DataLen)
{
	uint8_t Temp_Data[16], i, TempDataLen;
	BSP_EEP_WriteMoreBytes(EEaddr, Data, DataLen);
	//校验写入数据是否正确
	TempDataLen = DataLen>16 ? 16 : DataLen;
	BSP_EEPROM_Load(EEaddr, Temp_Data, TempDataLen);
	for (i = 0; i<TempDataLen; i++)
	{
		if (Temp_Data[i] != Data[i])
		{
			printf("Moorgen INFO : The data read is inconsistent with the data stored.\n");
			//Rs485_Tx_SaveErr(3);
			break;
		}
	}
	return(true);
}
//--------------------------------------------------------------
// 函数名称: BSP_EEPROM_Load
// 功能描述: 从EEPROM读取数据
// 输入参数: Data:数据指针 DataLen:数据长度 EEaddr:EEPROM起始地址
// 返回参数: true
//---------------------------------------------------------------
uint8_t BSP_EEPROM_Load(uint32_t EEaddr, uint8_t* Data, uint32_t DataLen)
{
	BSP_EEP_ReadMoreBytes(EEaddr, Data, DataLen);
	return(true);
}